package com.imrookie.wrap;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;

/**
 * 泛型包装类
 * @author wangjiyu@imdada.cn
 * @create 2019/1/2
 */
public class GenericWrap {
    private ClassWrap classWrap;//原始类型
    private List<GenericWrap> sub;//子泛型,嵌套泛型
    private boolean genericFlag;//泛型标识
    private String genericChar;//泛型字符,例如:T,K,V等

    public GenericWrap() {
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("{");
        sb.append("\"classWrap\":").append(classWrap);
        sb.append(", \"sub\":").append(sub);
        sb.append(", \"genericFlag\":").append(genericFlag);
        sb.append(", \"genericChar\":").append(genericChar != null ? "\"" : "").append(genericChar).append(genericChar != null ? "\"" : "");
        sb.append('}');
        return sb.toString();
    }

    public GenericWrap(Type type) {
        if (type instanceof ParameterizedType) {
            this.genericFlag = true;
            ParameterizedType pt = (ParameterizedType) type;//泛型类型
            try {
                this.classWrap = ClassWrap.getInstance(Class.forName(pt.getRawType().getTypeName()));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            if (pt.getActualTypeArguments() != null && pt.getActualTypeArguments().length > 0) {
                for (Type type1 : pt.getActualTypeArguments()) {
                    GenericWrap s = new GenericWrap(type1);
                    try {
                        //泛型的叶子节点补充类信息(放在这里而不放在else里面是因为else里面很多地方不论是不是泛型都会调到), 例如:List<A<B>>中的B就叫叶子(也就是底下再也没有泛型了)
                        //System.out.println(this.classWrap.getClassName()+"====="+type1.getTypeName());
                        if (type1.getTypeName().endsWith("[]")) {
                            s.setClassWrap(ClassWrap.getInstance(Class.forName(type1.getTypeName().replace("[]", ""))));
                        } else {
                            s.setClassWrap(ClassWrap.getInstance(Class.forName(type1.getTypeName())));
                        }
                    } catch (ClassNotFoundException e) {
                        //e.printStackTrace();
                    }
                    this.append(s);
                }
            }
        } else if (type instanceof TypeVariable) {
            this.genericFlag = true;
            this.genericChar = ((TypeVariable) type).getName();
        } else if (type instanceof GenericArrayType) {
            this.genericFlag = true;
            this.genericChar = ((GenericArrayType) type).getGenericComponentType().getTypeName() + "[]";
        } else {//普通类型,不属于泛型  例如: List就不是泛型, 如果是List<T>就走不到这里
            this.genericChar = type.getTypeName().substring(type.getTypeName().lastIndexOf(".") + 1);
            /*if (type.getTypeName().endsWith("[]")) {
                try {
                    this.classWrap = ClassWrap.getInstance(Class.forName(type.getTypeName().replace("[]", "")));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }*/
           /* try {
                this.classWrap = ClassWrap.getInstance(Class.forName(type.getTypeName()));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }*/
        }
    }

    public String toStatement() {
        if (!this.genericFlag || this.genericChar != null) {
            return this.genericChar;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(this.classWrap.getClassName());
        if (this.sub != null && this.sub.size() > 0) {
            sb.append("<");
            for (int i=0;i<this.sub.size();i++) {
                if (i == 0) {
                    sb.append(this.sub.get(i).toStatement());
                } else {
                    sb.append(", ");
                    sb.append(this.sub.get(i).toStatement());
                }
            }
            sb.append(">");
        }
        return sb.toString();
    }

    public void append(GenericWrap subGeneric){
        if (sub == null) {
            synchronized (this) {
                if (sub == null) {
                    sub = new ArrayList<GenericWrap>();
                }
            }
        }
        sub.add(subGeneric);
    }

    public ClassWrap getClassWrap() {
        return classWrap;
    }

    public void setClassWrap(ClassWrap classWrap) {
        this.classWrap = classWrap;
    }

    public List<GenericWrap> getSub() {
        return sub;
    }

    public void setSub(List<GenericWrap> sub) {
        this.sub = sub;
    }

    public boolean isGenericFlag() {
        return genericFlag;
    }

    public void setGenericFlag(boolean genericFlag) {
        this.genericFlag = genericFlag;
    }

    public String getGenericChar() {
        return genericChar;
    }

    public void setGenericChar(String genericChar) {
        this.genericChar = genericChar;
    }
}
